/**
=oj/term - A terminal interface

The term module provides a command-line interface for interacting with the system.

*/


window.TERM = {}



TERM.Term = function(container) {
    /**
     *=Term - Term object
     *
     */
    
    var self = {}
    
    
    var COMMANDS = {
         
        'cd': {
            'help': "cd 'path'      - Change the current working directory",
            'do': function (args) {
                self.print_style = 'term_files'
                OJ.OS.chdir(args[1], function() {
                    self.read('$cwd#', self.execute)
                })
                self.setprompt( '' )
            }
        },
        
        'cp': {
            'help': "cp 'src' 'dst' - Copy a file",
            'do': function (args) {
                args.shift()
                args[0] = OJ.OS.PATH.abspath(args[0])
                args[1] = OJ.OS.PATH.abspath(args[1])
                print('['+args+']')
                OJ.OS.concat( args, false, self.response)
                self.setprompt('')
            }
        },
        
        'help': {
            'help': "help           - List available commands",
            'do': function (args) {
                Object.keys(COMMANDS).forEach(function (cmd) {
                    self.print(COMMANDS[cmd]['help'])
                })
                self.response()
            }
        },
        
        'id': {
            'help': "id             - Get user identity",
            'do': function (args) {
                self.print(OJ.OS.environ.user.name)
                self.response()
            }
        },
        
        'logout': {
            'help': "logout         - Log current user out",
            'do': function (args) {
                OJ.OS.logout(document.location, function(m) {
                    document.location = m.logout
                });
            }
        },
        
        'ls': {
            'help': "ls ['path']    - List files",
            'do': function (args) {
                var dir = '-'
                
                args.shift()
                
                while (dir.charAt(0) === '-' && args.length > 0)
                    dir = args.shift()
                
                if (dir.charAt(0) === '-')
                    dir = '.'
                
                self.print_style = 'term_files'
                OJ.OS.listdir(dir, self.response)
                self.setprompt('')
            }
        },
        
        'mkdir': {
            'help': "mkdir 'path'   - Make a directory",
            'do': function (args) {
                OJ.OS.mkdir( args[ 1 ], self.response )
                self.setprompt('')
            }
        },
        
        'mv': {
            'help': "mv 'src' 'dst' - Move file or directory",
            'do': function (args) {
                OJ.OS.move(args[1], args[2], self.response)
                self.setprompt('')
            }
        },
        
        'echo': {
            'help': "echo           - Send to the terminal",
            'do': function (args) {
                self.print(args[1])
                self.response()
            }
        },
        
        'rm': {
            'help': "rm 'path'      - Remove file",
            'do': function (args) {
                OJ.OS.remove(args[1], self.response)
                self.setprompt('')
            }
        },
        
        'rmdir': {
            'help': "rmdir 'path'   - Remove directory",
            'do': function (args) {
                OJ.OS.rmdir(args[1], self.response)
                self.setprompt('')
            }
        },
        
        'time': {
            'help': "time           - Get current local time",
            'do': function (args) {
                self.print((new Date()).toLocaleString())
                self.response()
            }
        },
        
        'version': {
            'help': "version        - Get oj version",
            'do': function (args) {
                self.print(OJ.version)
                self.response()
            }
        }

    }

    
    
    self.print = function(output) {
        /**
         *>print(output)
         *
         * Writes output to the history buffer.
         *
         */
        
        if (self.buffer.length === OJ.OS.environ.term_history)
            self.history.removeChild(self.buffer.shift())
        
        if (!(output instanceof HTMLElement)) {
            if (typeof output === 'undefined') {
                output = '';
            } else if (typeof output === 'object') {
                if (output.hasOwnProperty('error'))
                    self.print_style = 'term_error'
                output = JSON.stringify(output)
            }
            output = output.replace(/", "|","|"]|"}/g, '\n')
            output = output.replace(/\["|{"|\[\]/g, '')
            output = output.replace(/":"|": "/g, ': ')
            output = output.replace(/\\\//g, '/')
        }
        
        output = OJ.element(self.history, 'div', 'term_print ' + self.print_style, [output])
        self.buffer.push(output)
        self.cmd.scrollIntoView()
        
        return output

    }
    
    
    self.read = function(prompt, fn) {
        /**
         *>read('prompt', callback)
         *
         * Read input from the user.
         *
         */
        
        self.setprompt(prompt)
        self.cmd.focus()
        self.callback = fn
        
        return self

    }

    
    
    self.setprompt = function(prompt) {
        /**
         *>setprompt('prompt')
         *
         * Updates the prompt component value.
         *
         */
        
        for (var prop in OJ.OS.environ)
            prompt = prompt.replace('$'+prop, OJ.OS.environ[prop])
        
        self.prm.textContent = prompt
        OJ.OS.environ.prompt = prompt
        self.layout()
        
        return self

    }

    
    
    self.response = function(response) {
        /**
         *>response(response)
         *
         * Prints the response and prompts for input.
         *
         */

        self.print(response)
        self.read('$cwd#', self.execute)

    }

    
    
    self.execute = function(input) {
        /**
         *>execute('input')
         *
         * Executes a pipe separated string of commands.
         *
         */
        
        var cmd = input.replace(/ +/g, ' ').split(' ')

        self.print_style = ''
        
        if (cmd[0] in COMMANDS)
            COMMANDS[cmd[0]]['do'](cmd)

        else {
            window.open((cmd.length > 1) ? '/' + cmd[0] + '?f=' + OJ.OS.PATH.abspath(cmd[1]) : '/' + cmd[0])
            self.response()
        }
        
        return self

    }

    
    
    self.layout = function() {
        /**
         *>layout()
         *
         * Updates the layout of the display.
         *
         */
        
        self.cmd.style.width = (self.panel.offsetWidth - self.prm.offsetWidth - 30) + 'px'
        
        return self
    }
    
    
        
    self.container = container
        
    self.container.style['background-color'] = '#111111'
        
    self.buffer   = []
    self.callback = null
    self.panel    = OJ.element(self.container, 'div', 'term_container')
    self.history  = OJ.element(self.panel, 'div', 'term_history')
    self.prm      = OJ.element(self.panel, 'span', 'term_prompt')
        
    self.print_style            = ''
    self.prm.style.paddingRight = '2px'
        
    self.cmd         = OJ.element(self.panel, 'input', 'term_cmdline', {'type': 'text'})
    self.cmd.onfocus = function() {self.cmd.style.outline='none'}
        
    self.panel.onresize = self.layout
    self.panel.onclick  = self.focus
        
    document.onclick = self.focus
        
    self.cmd.onkeypress = function(event) {
        if (event.keyCode != '13') return true
            
        var p = self.prm.cloneNode(true),
            input = self.cmd.value
        
        p.style.marginRight = '1px'
        self.cmd.value = ''
        
        self.print(OJ.element('span', '', [ p,
            OJ.element('span', 'term_cmdline', [input])
        ]))
            
        if (input.length > 0 && self.callback) {
            var fn = self.callback
            self.callback = null
            fn(input)
        }
    }
        
    OJ.OS.environ.term_history = 100
    
    return self
}


OJ.element(document.head, 'style', {'type': 'text/css'}, [
    '.term_container {',
    '  color: #cccccc;',
    '  border: 0;',
    '  margin: 0;',
    '  padding: 5px;',
    '  font: normal normal normal 16pt monospace;',
    '  white-space: pre;',
    '}',
    '.term_history {',
    '}',
    '.term_prompt {',
    '  color: white;',
    '}',
    '.term_cmdline {',
    '  color: #cccccc;',
    '  background: none;',
    '  font: normal normal normal 16pt monospace;',
    '  white-space: pre;',
    '  border: 0;',
    '}',
    '.term_print {',
    '  padding-top: 3px;',
    '}',
    '.term_files {',
    '  color: #00ff00;',
    '}',
    '.term_error {',
    '  color: #ff0000;',
    '}'
])


if (OJ.__main__ === 'oj/term') {
    /**
     *=Main application
     *
     * When run as the main application this module will automatically
     * create a Term instance using document.body as the container.
     *
     * Available commands
     *
     *./# help
     *.cd 'path'      - Change the current working directory
     *.cp 'src' 'dst' - Copy a file
     *.help           - List available commands
     *.id             - Get user identity
     *.logout         - Log current user out
     *.ls ['path']    - List files
     *.mkdir 'path'   - Make a directory
     *.mv 'src' 'dst' - Move file or directory
     *.echo           - Send to the terminal
     *.rm 'path'      - Remove file
     *.rmdir 'path'   - Remove directory
     *.time           - Get current local time
     *.version        - Get oj version 
     *
     */
    
    OJ.OS.identity(document.location, function(m) {
        
        if (m.hasOwnProperty('login')) {
            document.location = m.login
            return
        }
        
        OJ.OS.environ.user = m
        
        var sh = TERM.Term(document.body),
            p = '/'
        
        sh.print('Welcome ' + OJ.OS.environ.user.name)
        sh.print((new Date()).toLocaleString())
        sh.print(OJ.version)
        sh.print()
        
        OJ.args.forEach(function(arg) {
          if (arg[0] === 'p')
              p = arg[1]
        })

        OJ.OS.chdir(p, function() {
            sh.read('$cwd#', sh.execute)
        })
        
        
    })
    
    OJ.element(document.head, 'syle', {'type': 'text/css'}, [
        'html {',
        '  height: 100%;',
        '}',
        'body {',
        '  height: 100%;',
        '}'
    ])
}

